using System;
using System.Collections;
using SMS.SMPPClient.PDU.Incoming;
using SMS.SMPPClient.PDU;

namespace SMS.SMPPClient.Util
{
    /// <summary>
    /// Takes incoming packets from an input stream and generates
    /// PDUs based on the command field.
    /// </summary>
    public class PDUFactory
    {
        /// <summary>
        /// Constructor.
        /// </summary>
        public PDUFactory()
        {
        }

        /// <summary>
        /// Factory method to generate the PDU.
        /// </summary>
        /// <param name="incomingPDUs">The SMSC response.</param>
        /// <returns>The PDU.</returns>
        public Queue GetPDUQueue(byte[] incomingPDUs)
        {
            Queue packetQueue = new Queue();

            //get the first packet
            byte[] response = null;
            SMPPResponse packet = null;
            int newLength = 0;

            //this needs to start at zero
            uint CommandLength = 0;

            //------------------------

            //look for multiple PDUs in the response
            while (incomingPDUs.Length > 0)
            {
                //determine if we have another response PDU after this one
                newLength = (int)(incomingPDUs.Length - CommandLength);

                //could be empty data or it could be a PDU
                if (newLength > 0)
                {
                    //get the next PDU
                    response = SMPPResponse.TrimResponsePDU(incomingPDUs);

                    //there could be none...
                    if (response.Length > 0)
                    {
                        //get the command length and command ID
                        CommandLength = SMPPResponse.DecodeCommandLength(response);

                        //trim the packet down so we can look for more PDUs
                        incomingPDUs = SMPPResponse.ByteArrayCopy(incomingPDUs, CommandLength);

                        if (CommandLength > 0)
                        {
                            //process
                            packet = GetPDU(response);

                            if (packet != null)
                                packetQueue.Enqueue(packet);
                        }
                    }
                    else
                    {
                        //kill it off and return
                        incomingPDUs = new Byte[0];
                    }
                }
            }

            return packetQueue;
        }

        /// <summary>
        /// Gets a single PDU based on the response bytes.
        /// </summary>
        /// <param name="response">The SMSC response.</param>
        /// <returns>The PDU corresponding to the bytes.</returns>
        private SMPPResponse GetPDU(byte[] response)
        {
            SMS.SMPPClient.PDU.PDU.CommandIDType commandID =
                SMPPResponse.DecodeCommandID(response);
            SMPPResponse packet;

            switch (commandID)
            {
                case SMS.SMPPClient.PDU.PDU.CommandIDType.alert_notification:
                    packet = new SMPPAlertNotification(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.bind_receiver_resp:
                case SMS.SMPPClient.PDU.PDU.CommandIDType.bind_transceiver_resp:
                case SMS.SMPPClient.PDU.PDU.CommandIDType.bind_transmitter_resp:
                    packet = new SMPPBindResponse(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.cancel_sm_resp:
                    packet = new SMPPCancelSMResponse(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.data_sm_resp:
                    packet = new SMPPDataSMResponse(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.deliver_sm_resp:
                    packet = new SMPPDeliverSM(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.enquire_link_resp:
                    packet = new SMPPEnquireLinkResponse(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.outbind:
                    packet = new SMPPOutbind(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.query_sm_resp:
                    packet = new SMPPQuerySMResponse(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.replace_sm_resp:
                    packet = new SMPPReplaceSMResponse(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.submit_multi_resp:
                    packet = new SMPPSubmitMultiResponse(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.submit_sm_resp:
                    packet = new SMPPSubmitSMResponse(response);
                    break;
                case SMS.SMPPClient.PDU.PDU.CommandIDType.unbind_resp:
                    packet = new SMPPUnbindResponse(response);
                    break;
                default:
                    packet = null;
                    break;
            }

            return packet;
        }
    }
}
